use crate::rtsp::rtp::rtcp::define::RTCP_RR;
use crate::rtsp::rtp::rtcp::rtcp_app::RtcpApp;
use crate::rtsp::rtp::rtcp::rtcp_header::RtcpHeader;
use crate::rtsp::rtp::rtcp::rtcp_rr::{ReportBlock, RtcpReceiverReport};
use crate::rtsp::rtp::rtcp::rtcp_sr::RtcpSenderReport;
use crate::rtsp::rtp::{utils, RtpPacket};
use bytes::BytesMut;

// 计算两个 16 位序列号之间的距离
pub fn distance(new: u16, old: u16) -> u16 {
    if new < old {
        65535 - old + new + 1
    } else {
        new - old
    }
}

// 定义最小连续接收到的数据包数量，用于判断源是否有效
const MIN_SEQUENTIAL: u32 = 2;
// 定义 RTP 序列号的模数，即 2^16，因为 RTP 序列号是 16 位的
const RTP_SEQ_MOD: u32 = 1 << 16;
// 定义允许的最大丢包数量
const MAX_DROPOUT: u32 = 3000;
// 定义允许的最大乱序数量
const MAX_MISORDER: u32 = 100;

// RtcpSource 结构体，用于记录每个同步源的状态信息
#[derive(Debug, Clone, Default)]
struct RtcpSource {
    // 最高序列号
    max_seq: u16,
    // 序列号回绕的次数
    cycles: u32,
    // 基础序列号
    base_seq: u32,
    // 最后一个 '坏' 序列号 + 1
    bad_seq: u32,
    // 达到有效源所需的连续数据包数量
    probation: u32,
    // 已接收的数据包数量
    received: u32,
    // 上一个间隔预期接收的数据包数量
    expected_prior: u32,
    // 上一个间隔实际接收的数据包数量
    received_prior: u32,
    // 估计的数据包到达时间抖动
    jitter: f64,
}

impl RtcpSource {
    fn update_sequence(&mut self, seq: u16) -> usize {
        // 计算新序列号与当前最大序列号之间的距离
        let delta = distance(seq, self.max_seq);

        if self.probation > 0 {
            /* 数据包按顺序到达 */
            if seq == self.max_seq + 1 {
                // 连续接收到的数据包数量减 1
                self.probation -= 1;
                // 更新最大序列号
                self.max_seq = seq;
                if self.probation == 0 {
                    // 达到最小连续数据包数量，初始化序列号相关状态
                    self.init_seq(seq);
                    // 已接收数据包数量加 1
                    self.received += 1;
                    return 1;
                }
            } else {
                // 序列号不连续，重置连续数据包计数
                self.probation = MIN_SEQUENTIAL - 1;
                // 更新最大序列号
                self.max_seq = seq;
            }
            return 0;
        } else if delta < MAX_DROPOUT as u16 {
            /* 按顺序到达，允许有一定的间隙 */
            if seq < self.max_seq {
                /*
                 * 序列号回绕 - 增加序列号回绕次数
                 */
                self.cycles += RTP_SEQ_MOD;
            }
            // 更新最大序列号
            self.max_seq = seq;
        } else if delta as u32 <= RTP_SEQ_MOD - MAX_MISORDER {
            if seq == self.bad_seq as u16 {
                /*
                 * 两个连续的数据包 -- 假设对方在未通知的情况下重启，重新同步
                 * （即，假装这是第一个数据包）
                 */
                self.init_seq(seq);
            } else {
                // 记录新的 '坏' 序列号
                self.bad_seq = (seq as u32 + 1) & (RTP_SEQ_MOD - 1);
                return 0;
            }
        } else {
            /* 重复或乱序的数据包 */
        }
        // 已接收数据包数量加 1
        self.received += 1;

        1
    }

    // 初始化序列号相关的状态信息
    fn init_seq(&mut self, seq: u16) {
        // 设置基础序列号
        self.base_seq = seq as u32;
        // 设置最大序列号
        self.max_seq = seq;
        // 设置 '坏' 序列号，确保初始时 seq != bad_seq
        self.bad_seq = RTP_SEQ_MOD + 1;
        // 重置序列号回绕次数
        self.cycles = 0;
        // 重置已接收数据包数量
        self.received = 0;
        // 重置上一个间隔预期接收的数据包数量
        self.received_prior = 0;
        // 重置上一个间隔实际接收的数据包数量
        self.expected_prior = 0;

        // 其他初始化
        // 再次设置基础序列号
        self.base_seq = seq as u32;
        // 再次设置最大序列号
        self.max_seq = seq;
        // 再次设置 '坏' 序列号
        self.bad_seq = RTP_SEQ_MOD + 1;
    }
}

// RtcpContext 结构体，用于管理 RTCP 上下文信息
#[derive(Debug, Clone, Default)]
pub struct RtcpContext {
    // 本地同源标识符
    ssrc: u32,
    // 发送方同源标识符
    sender_ssrc: u32,
    // 上次收到报告的 NTP 时间戳
    sr_ntp_lsr: u64,
    // 上次收到发送报告的时钟
    sr_clock_time: u64,
    // 上次收到 RTP 数据包的时钟时间
    last_rtp_clock: u64,
    // 上次收到的 RTP 数据包的时间戳
    last_rtp_timestamp: u32,
    // 采样率
    sample_rate: u32,
    // 已发送的字节数
    send_bytes: u64,
    // 已发送的数据包数量
    send_packets: u64,

    // 同步源状态信息
    source: RtcpSource,
}

impl RtcpContext {
    pub fn new(ssrc: u32, seq: u16, sample_rate: u32) -> Self {
        RtcpContext {
            ssrc,
            source: RtcpSource {
                // 初始最大序列号为初始序列号减 1
                max_seq: seq - 1,
                // 初始连续数据包计数为最小连续数据包数量
                probation: MIN_SEQUENTIAL,
                ..Default::default()
            },

            sample_rate,
            ..Default::default()
        }
    }

    // 生成一个 RTCP APP 类型数据包
    pub fn generate_app(&self, name: String, data: BytesMut) -> RtcpApp {
        // 创建一个可变字节缓冲区，容量为名称的长度
        let mut buf = BytesMut::with_capacity(name.len());
        // 将名称的字节数据添加到缓冲区
        buf.extend_from_slice(name.as_bytes());

        RtcpApp {
            ssrc: self.ssrc,
            name: buf,
            app_data: data,
            ..Default::default()
        }
    }

    // 生成一个 RTCP 接收报告块
    fn gen_report_block(&mut self) -> ReportBlock {
        // 计算扩展的最大序列号，考虑序列号回绕
        let extend_max = self.source.cycles + self.source.max_seq as u32;
        // 计算预期接收的数据包数量
        let expected = extend_max - self.source.base_seq + 1;
        // 计算丢失的数据包数量
        let lost = expected - self.source.received;
        // 计算当前间隔预期接收的数据包数量
        let expected_interval = expected - self.source.expected_prior;
        // 更新上一个间隔预期接收的数据包数量
        self.source.expected_prior = expected;

        // 计算当前间隔实际接收的数据包数量
        let received_interval = self.source.received - self.source.received_prior;
        // 更新上一个间隔实际接收的数据包数量
        self.source.received_prior = self.source.received;
        // 计算当前间隔丢失的数据包数量
        let lost_interval = expected_interval as i64 - received_interval as i64;

        // 计算丢包率的分数部分
        let fraction = if expected_interval == 0 || lost_interval < 0 {
            0
        } else {
            ((lost_interval as u32) << 8) / expected_interval
        };

        // 计算自上次收到发送报告以来的延迟
        let delay = utils::current_time() - self.sr_clock_time;
        // 提取上次收到的发送报告中的 NTP 时间戳的中间 32 位
        let lsr = self.sr_ntp_lsr >> 8 & 0xFFFFFFFF;
        // 计算延迟的 DLSR 值
        let dlsr = (delay as f64 / 1000000. * 65535.) as u32;

        ReportBlock {
            cumutlative_num_of_packets_lost: lost,
            fraction_lost: fraction as u8,
            extended_highest_seq_number: extend_max,
            lsr: lsr as u32,
            dlsr,
            ssrc: self.sender_ssrc,
            jitter: self.source.jitter as u32,
        }
    }

    // 生成一个 RTCP 接收报告（RR）数据包
    pub fn generate_rr(&mut self) -> RtcpReceiverReport {
        // 生成一个接收报告块
        let block = self.gen_report_block();

        RtcpReceiverReport {
            header: RtcpHeader {
                payload_type: RTCP_RR, // 负载类型为 RTCP 接收报告
                report_count: 1,       // 报告块数量为 1
                version: 2,            // RTCP 版本号为 2
                length: (4 + 24) / 4,  // 头部长度
                ..Default::default()
            },
            report_blocks: vec![block], // 包含一个接收报告块
            ssrc: self.ssrc,            // 本地 SSRC
        }
    }

    // 发送 RTP 数据包
    pub fn send_rtp(&mut self, pkt: RtpPacket) {
        // 更新已发送的字节数
        self.send_bytes += pkt.payload.len() as u64;
        // 更新已发送的数据包数量
        self.send_packets += 1;
        // 更新上次发送的 RTP 数据包的时间戳
        self.last_rtp_timestamp = pkt.header.timestamp;
    }

    // 处理收到 RTCP 发送报告（SR）
    pub fn received_sr(&mut self, sr: &RtcpSenderReport) {
        // 更新收到发送报告的时钟时间
        self.sr_clock_time = utils::current_time();

        // 更新上次收到的发送报告中的 NTP 时间戳
        self.sr_ntp_lsr = sr.ntp;
        // 更新发送方的 SSRC
        self.sender_ssrc = sr.ssrc;
    }

    // 处理收到 RTP 数据包
    pub fn received_rtp(&mut self, pkt: RtpPacket) {
        // 更新序列号并检查数据包是否有效
        if 0 == self.source.update_sequence(pkt.header.seq_number) {
            return;
        }

        // 获取当前时钟时间
        let rtp_clock = utils::current_time();
        if self.last_rtp_clock == 0 {
            // 首次收到 RTP 数据包，初始化抖动值
            self.source.jitter = 0.;
        } else {
            // 计算时钟时间差对应的采样时间差
            let mut d = ((rtp_clock - self.last_rtp_clock) * self.sample_rate as u64 / 1000000)
                as i64
                - (pkt.header.timestamp - self.last_rtp_timestamp) as i64;

            if d < 0 {
                // 取绝对值
                d = -d;
            }
            // 更新抖动值
            self.source.jitter += (d as f64 - self.source.jitter) / 16.;
        }

        // 更新上次收到 RTP 数据包的时钟时间
        self.last_rtp_clock = rtp_clock;
        // 更新上次收到的 RTP 数据包的时间戳
        self.last_rtp_timestamp = pkt.header.timestamp;
    }
}
